/*==========================================================================
 * 
 * FindAction.java
 * 
 * $Author: randallco $
 * $Revision: 1.1 $
 * $Date: 2006/03/20 01:11:55 $
 * 
 * Created on 19-Mar-2006
 * Created by Marcel Palko alias Randallco on behalf of uwe_ewald 
 *==========================================================================*/
package net.sourceforge.ehep.actions;

import java.text.MessageFormat;

import net.sourceforge.ehep.EhepPlugin;
import net.sourceforge.ehep.core.Utils;
import net.sourceforge.ehep.editors.HexEditor;
import net.sourceforge.ehep.gui.HexEditorControl;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;

public class FindAction extends Action implements IPartListener {
	private class FindDialog extends Dialog implements Listener {
		private Combo fCombo;
		private Button fCase;
		private Button fWrap;
		private Button fHex;
		private Button fText;
		private boolean fHexTextSelectionChanged;
		private Label fMsgLabel;

		public FindDialog(Shell parentShell) {
			super(parentShell);
			setShellStyle(96);
		}

		protected void configureShell(Shell newShell) {
			super.configureShell(newShell);
			newShell.setText("Find text");
		}

		protected Control createDialogArea(Composite parent) {
			parent.setLayout(new GridLayout(2, false));
			fCombo = new Combo(parent, SWT.DROP_DOWN);
			if (fSettings != null)
				fillCombo(fCombo, fSettings.getArray(KEY_VALUE), fValue);
			GridData grid = new GridData();
			grid.horizontalSpan = 2;
			grid.horizontalAlignment = 4;
			fCombo.setLayoutData(grid);
			fCombo.setFocus();
			fWrap = new Button(parent, SWT.CHECK);
			fWrap.setText("&Wrap");
			fWrap.setSelection(fWrapAround);
			fCase = new Button(parent, SWT.CHECK);
			fCase.setText("Case sensitive");
			fCase.setSelection(fCaseSensitive);
			fHex = new Button(parent, SWT.RADIO);
			fHex.setText("Hex");
			fHex.addListener(SWT.Selection, this);
			fHex.setSelection(!fTextSelected);
			fText = new Button(parent, SWT.RADIO);
			fText.setText("Text");
			fText.setSelection(fTextSelected);
			fText.addListener(SWT.Selection, this);
			
			fMsgLabel = new Label(parent, 0);
			grid = new GridData();
			grid.horizontalSpan = 2;
			grid.horizontalAlignment = 4;
			fMsgLabel.setLayoutData(grid);
			return parent;
		}

		protected Control createContents(Composite parent) {
			Control control = super.createContents(parent);
			update();
			return control;
		}

		public void okPressed() {
			fValue = fCombo.getText();
			fCaseSensitive = fCase.getSelection();
			fWrapAround = fWrap.getSelection();
			fSettings.put(KEY_VALUE, addEntry(fSettings
					.getArray(KEY_VALUE), fValue, 10));
			fSettings.put(KEY_WRAP, fWrapAround);
			fSettings.put(KEY_CASE, fCaseSensitive);
			fSettings.put(KEY_TXT_SELECTED, fTextSelected);

			if (fFindReplaceTarget == null)
				return;
			Point pos = fFindReplaceTarget.getPosition();
			String hexFindValue = fHex.getSelection() ? fValue : Utils.charsToHex(fValue);
			hexFindValue = Utils.zeroPadding(hexFindValue, (int) (Math.ceil((double) hexFindValue.length() / 2) * 2));
			Point found = fFindReplaceTarget.findAndSelect(pos,
					hexFindValue, true, fCaseSensitive);
			if (fWrapAround && found == null) {
				found = fFindReplaceTarget.findAndSelect(new Point(0, 0), hexFindValue, true,
						fCaseSensitive);
				if (found != null) {
					getShell().getDisplay().beep();
					setMessage("End of buffer reached, continued at top");
					return;
				}
			}
			if (found == null) {
				String msg = MessageFormat.format("Text not found",
						new Object[] { fValue });
				setStatusMessage(msg);
				getShell().getDisplay().beep();
				setMessage(msg);
			} else {
				setStatusMessage(null);
				setMessage("");
			}
		}
		
		private void setMessage(String text) {
			fMsgLabel.setText(text);
			setStatusMessage(text);
		}

		public void setEnabled(boolean enabled) {
			if (fCombo == null) {
				return;
			} else {
				fCombo.setEnabled(enabled);
				fCase.setEnabled(enabled && !fHex.getSelection());
				fWrap.setEnabled(enabled);
				getButton(0).setEnabled(enabled);
				return;
			}
		}

		public boolean close() {
			setStatusMessage(null);
			return super.close();
		}

		private void hexSelected() {
			fCase.setEnabled(false);
			fCombo.setText(Utils.charsToHex(fCombo.getText()));
			fTextSelected = false;
		}

		private void textSelected() {
			fCase.setEnabled(true);
			fCombo.setText(Utils.hexToChars(fCombo.getText()));
			fTextSelected = true;
		}

		public void handleEvent(Event event) {
			if (event.type != SWT.Selection)
				return;
			Button button = (Button) event.widget;
			if (!button.getSelection())
				fHexTextSelectionChanged = true;
			else {
				if (!fHexTextSelectionChanged)
					return;
				fHexTextSelectionChanged = false;
				if (fHex == button)
					hexSelected();
				else if (fText == button)
					textSelected();
			}
		}
	};

	private static final String KEY_SECTION = "find";
	private static final String KEY_VALUE = "values";
	private static final String KEY_WRAP = "wrap";
	private static final String KEY_CASE = "case";
	private static final String KEY_TXT_SELECTED = "textSelected";

	private String fValue;
	private boolean fCaseSensitive;
	private boolean fWrapAround;
	private IDialogSettings fSettings;
	private FindDialog fDialog;
	private IStatusLineManager fStatusLine;
	private HexEditorControl fFindReplaceTarget;
	private boolean fTextSelected = true;

	public FindAction() {
		super("Find");
		fSettings = EhepPlugin.getDefault().getDialogSettings();
		IDialogSettings section = fSettings.getSection(KEY_SECTION);
		fSettings = section == null ? fSettings.addNewSection(KEY_SECTION) : section;
	}

	public void run() {
		String tmp[] = fSettings.getArray(KEY_VALUE);
		fValue = tmp == null || tmp.length <= 0 ? "" : tmp[0];
		fWrapAround = fSettings.getBoolean(KEY_WRAP);
		fCaseSensitive = fSettings.getBoolean(KEY_CASE);
		fTextSelected = fSettings.getBoolean(KEY_TXT_SELECTED);
		IWorkbenchWindow window = PlatformUI.getWorkbench()
				.getActiveWorkbenchWindow();
		if (window == null)
			return;
		if (fDialog != null) {
			fDialog.fCombo.setFocus();
		} else {
			fDialog = new FindDialog(window.getShell());
			window.getPartService().addPartListener(this);
			IWorkbenchPage page = window.getActivePage();
			if (page != null)
				partActivated(page.getActivePart());
		}
		fDialog.open();
		fDialog = null;
		window.getPartService().removePartListener(this);
	}

	private void setStatusMessage(String msg) {
		if (fStatusLine != null)
			fStatusLine.setErrorMessage(msg);
	}

	private void setStatusLineManager(IWorkbenchPart part) {
		if (part == null)
			return;
		IWorkbenchPartSite partSite = part.getSite();
		IActionBars actionBars = null;
		if (partSite instanceof IEditorSite)
			actionBars = ((IEditorSite) partSite).getActionBars();
		if (partSite instanceof IViewSite)
			actionBars = ((IViewSite) partSite).getActionBars();
		if (actionBars != null)
			fStatusLine = actionBars.getStatusLineManager();
	}

	public void partActivated(IWorkbenchPart part) {
		setStatusLineManager(part);
		update();
	}

	public void partBroughtToTop(IWorkbenchPart part) {
		setStatusLineManager(part);
	}

	public void partClosed(IWorkbenchPart part) {
		setStatusLineManager(part);
	}

	public void partDeactivated(IWorkbenchPart part) {
		setStatusLineManager(part);
		setStatusMessage(null);
	}

	public void partOpened(IWorkbenchPart part) {
		setStatusLineManager(part);
	}

	public void update() {
		IWorkbenchPart part = PlatformUI.getWorkbench()
				.getActiveWorkbenchWindow().getActivePage().getActivePart();
		if (part instanceof HexEditor)
			fFindReplaceTarget = ((HexEditor) part).getControl();
		else
			fFindReplaceTarget = null;
		setEnabled(fFindReplaceTarget != null);
		if (fDialog != null)
			fDialog.setEnabled(isEnabled());
	}

	public static void fillCombo(Combo combo, String array[], String def) {
		combo.removeAll();
		if (array == null || array.length == 0) {
			combo.setText(def);
			return;
		}
		for (int i = 0; i < array.length; i++)
			combo.add(array[i]);

		combo.setText(def == null ? array[0] : def);
	}

	public static String[] addEntry(String array[], String entry, int max) {
		if (array == null || array.length == 0)
			return (new String[] { entry });
		max = max <= 0 || max >= array.length ? array.length : max;
		for (int i = 0; i < max; i++)
			if (entry.equals(array[i])) {
				if (i > 0) {
					String tmp = array[i];
					System.arraycopy(array, 0, array, 1, i);
					array[0] = tmp;
				}
				String newArray[] = new String[max];
				System.arraycopy(array, 0, newArray, 0, max);
				return newArray;
			}

		String newArray[] = new String[max + 1];
		System.arraycopy(array, 0, newArray, 1, max);
		newArray[0] = entry;
		return newArray;
	}

}
